﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static StackExchange.Redis.Role;

namespace iot.Protocol.Modbus
{
    public class ModbusReadConverter
    {

        /// <summary>
        /// 将单个寄存器转换为 int16 (有符号16位整数)
        /// </summary>
        /// <param name="register">Modbus寄存器值</param>
        /// <param name="swapBytes">是否交换字节顺序</param>
        public static short ToInt16(ushort register, bool swapBytes = false)
        {
            ushort value = swapBytes ? (ushort)((register >> 8) | (register << 8)) : register;
            return (short)value;
        }

        /// <summary>
        /// 将单个寄存器转换为 uint16 (无符号16位整数)
        /// </summary>
        /// <param name="register">Modbus寄存器值</param>
        /// <param name="swapBytes">是否交换字节顺序</param>
        public static ushort ToUInt16(ushort register, bool swapBytes = false)
        {
            return swapBytes ? (ushort)((register >> 8) | (register << 8)) : register;
        }

        /// <summary>
        /// 将寄存器数组转换为 int16 数组
        /// </summary>
        /// <param name="registers">Modbus寄存器数组</param>
        /// <param name="swapBytes">是否交换字节顺序</param>
        public static short[] ToInt16Array(ushort[] registers, bool swapBytes = false)
        {
            short[] result = new short[registers.Length];
            for (int i = 0; i < registers.Length; i++)
            {
                result[i] = ToInt16(registers[i], swapBytes);
            }
            return result;
        }

        /// <summary>
        /// 将寄存器数组转换为 uint16 数组
        /// </summary>
        /// <param name="registers">Modbus寄存器数组</param>
        /// <param name="swapBytes">是否交换字节顺序</param>
        public static ushort[] ToUInt16Array(ushort[] registers, bool swapBytes = false)
        {
            ushort[] result = new ushort[registers.Length];
            for (int i = 0; i < registers.Length; i++)
            {
                result[i] = ToUInt16(registers[i], swapBytes);
            }
            return result;
        }

        /// <summary>
        /// 将寄存器转换为 int32 (有符号32位整数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static int ToInt32(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length %2 !=0)
                throw new ArgumentException("需要2个寄存器来转换int32");

            byte[] bytes = ConvertToBytes(registers, endianness);
            return BitConverter.ToInt32(bytes, 0);
        }

        /// <summary>
        /// 将寄存器转换为 uint32 (无符号32位整数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static uint ToUInt32(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length %2!=0)
                throw new ArgumentException("需要2个寄存器来转换uint32");

            byte[] bytes = ConvertToBytes(registers, endianness);
            return BitConverter.ToUInt32(bytes, 0);
        }

        private static byte[] ConvertToBytes(ushort[] registers, string endianness)
        {
            byte[] bytes = new byte[4];

            switch (endianness)
            {
                case "ABCD": // 大端序 (默认)
                    bytes[0] = (byte)(registers[0] >> 8);
                    bytes[1] = (byte)registers[0];
                    bytes[2] = (byte)(registers[1] >> 8);
                    bytes[3] = (byte)registers[1];
                    break;

                case "BADC": // 字节交换
                    bytes[0] = (byte)registers[0];
                    bytes[1] = (byte)(registers[0] >> 8);
                    bytes[2] = (byte)registers[1];
                    bytes[3] = (byte)(registers[1] >> 8);
                    break;

                case "CDAB": // 字交换
                    bytes[0] = (byte)(registers[1] >> 8);
                    bytes[1] = (byte)registers[1];
                    bytes[2] = (byte)(registers[0] >> 8);
                    bytes[3] = (byte)registers[0];
                    break;

                case "DCBA": // 字节和字都交换
                    bytes[0] = (byte)registers[1];
                    bytes[1] = (byte)(registers[1] >> 8);
                    bytes[2] = (byte)registers[0];
                    bytes[3] = (byte)(registers[0] >> 8);
                    break;

                default:
                    throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC, CDAB, DCBA");
            }

            // 如果系统是小端序，需要反转字节数组
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }
            return bytes;
        }

        /// <summary>
        /// 将寄存器转换为 int64 (有符号64位整数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static long ToInt64(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length %4!=0)
                throw new ArgumentException("需要4个寄存器来转换int64");

            byte[] bytes = ConvertToBytes64(registers, endianness);
            return BitConverter.ToInt64(bytes, 0);
        }

        /// <summary>
        /// 将寄存器转换为 uint64 (无符号64位整数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static ulong ToUInt64(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length % 4 != 0)
                throw new ArgumentException("需要4个寄存器来转换uint64");

            byte[] bytes = ConvertToBytes64(registers, endianness);
            return BitConverter.ToUInt64(bytes, 0);
        }

        private static byte[] ConvertToBytes64(ushort[] registers, string endianness)
        {
            byte[] bytes = new byte[8];

            switch (endianness)
            {
                case "ABCD": // 大端序 (默认)
                    bytes[0] = (byte)(registers[0] >> 8);
                    bytes[1] = (byte)registers[0];
                    bytes[2] = (byte)(registers[1] >> 8);
                    bytes[3] = (byte)registers[1];
                    bytes[4] = (byte)(registers[2] >> 8);
                    bytes[5] = (byte)registers[2];
                    bytes[6] = (byte)(registers[3] >> 8);
                    bytes[7] = (byte)registers[3];
                    break;

                case "BADC": // 字节交换
                    bytes[0] = (byte)registers[0];
                    bytes[1] = (byte)(registers[0] >> 8);
                    bytes[2] = (byte)registers[1];
                    bytes[3] = (byte)(registers[1] >> 8);
                    bytes[4] = (byte)registers[2];
                    bytes[5] = (byte)(registers[2] >> 8);
                    bytes[6] = (byte)registers[3];
                    bytes[7] = (byte)(registers[3] >> 8);
                    break;

                case "CDAB": // 字交换
                    bytes[0] = (byte)(registers[3] >> 8);
                    bytes[1] = (byte)registers[3];
                    bytes[2] = (byte)(registers[2] >> 8);
                    bytes[3] = (byte)registers[2];
                    bytes[4] = (byte)(registers[1] >> 8);
                    bytes[5] = (byte)registers[1];
                    bytes[6] = (byte)(registers[0] >> 8);
                    bytes[7] = (byte)registers[0];
                    break;

                case "DCBA": // 字节和字都交换
                    bytes[0] = (byte)registers[3];
                    bytes[1] = (byte)(registers[3] >> 8);
                    bytes[2] = (byte)registers[2];
                    bytes[3] = (byte)(registers[2] >> 8);
                    bytes[4] = (byte)registers[1];
                    bytes[5] = (byte)(registers[1] >> 8);
                    bytes[6] = (byte)registers[0];
                    bytes[7] = (byte)(registers[0] >> 8);
                    break;

                default:
                    throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC, CDAB, DCBA");
            }

            // 如果系统是小端序，需要反转字节数组
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }

            return bytes;
        }

        /// <summary>
        /// 将寄存器转换为 float (32位单精度浮点数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static float ToFloat(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length != 2)
                throw new ArgumentException("需要2个寄存器来转换float");

            byte[] bytes = ConvertToBytes32(registers, endianness);
            return BitConverter.ToSingle(bytes, 0);
        }

        /// <summary>
        /// 将寄存器转换为 double (64位双精度浮点数)
        /// </summary>
        /// <param name="registers">Modbus寄存器值</param>
        /// <param name="endianness">字节顺序: ABCD, BADC, CDAB, DCBA</param>
        public static double ToDouble(ushort[] registers, string endianness = "ABCD")
        {
            if (registers.Length != 4)
                throw new ArgumentException("需要4个寄存器来转换double");

            byte[] bytes = ConvertToBytesDouble64(registers, endianness);
            return BitConverter.ToDouble(bytes, 0);
        }

        private static byte[] ConvertToBytes32(ushort[] registers, string endianness)
        {
            byte[] bytes = new byte[4];

            switch (endianness)
            {
                case "ABCD": // 大端序 (默认)
                    bytes[0] = (byte)(registers[0] >> 8);
                    bytes[1] = (byte)registers[0];
                    bytes[2] = (byte)(registers[1] >> 8);
                    bytes[3] = (byte)registers[1];
                    break;

                case "BADC": // 字节交换
                    bytes[0] = (byte)registers[0];
                    bytes[1] = (byte)(registers[0] >> 8);
                    bytes[2] = (byte)registers[1];
                    bytes[3] = (byte)(registers[1] >> 8);
                    break;

                case "CDAB": // 字交换
                    bytes[0] = (byte)(registers[1] >> 8);
                    bytes[1] = (byte)registers[1];
                    bytes[2] = (byte)(registers[0] >> 8);
                    bytes[3] = (byte)registers[0];
                    break;

                case "DCBA": // 字节和字都交换
                    bytes[0] = (byte)registers[1];
                    bytes[1] = (byte)(registers[1] >> 8);
                    bytes[2] = (byte)registers[0];
                    bytes[3] = (byte)(registers[0] >> 8);
                    break;

                default:
                    throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC, CDAB, DCBA");
            }

            // 如果系统是小端序，需要反转字节数组
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }

            return bytes;
        }

        private static byte[] ConvertToBytesDouble64(ushort[] registers, string endianness)
        {
            byte[] bytes = new byte[8];

            switch (endianness)
            {
                case "ABCD": // 大端序 (默认)
                    bytes[0] = (byte)(registers[0] >> 8);
                    bytes[1] = (byte)registers[0];
                    bytes[2] = (byte)(registers[1] >> 8);
                    bytes[3] = (byte)registers[1];
                    bytes[4] = (byte)(registers[2] >> 8);
                    bytes[5] = (byte)registers[2];
                    bytes[6] = (byte)(registers[3] >> 8);
                    bytes[7] = (byte)registers[3];
                    break;

                case "BADC": // 字节交换
                    bytes[0] = (byte)registers[0];
                    bytes[1] = (byte)(registers[0] >> 8);
                    bytes[2] = (byte)registers[1];
                    bytes[3] = (byte)(registers[1] >> 8);
                    bytes[4] = (byte)registers[2];
                    bytes[5] = (byte)(registers[2] >> 8);
                    bytes[6] = (byte)registers[3];
                    bytes[7] = (byte)(registers[3] >> 8);
                    break;

                case "CDAB": // 字交换
                    bytes[0] = (byte)(registers[3] >> 8);
                    bytes[1] = (byte)registers[3];
                    bytes[2] = (byte)(registers[2] >> 8);
                    bytes[3] = (byte)registers[2];
                    bytes[4] = (byte)(registers[1] >> 8);
                    bytes[5] = (byte)registers[1];
                    bytes[6] = (byte)(registers[0] >> 8);
                    bytes[7] = (byte)registers[0];
                    break;

                case "DCBA": // 字节和字都交换
                    bytes[0] = (byte)registers[3];
                    bytes[1] = (byte)(registers[3] >> 8);
                    bytes[2] = (byte)registers[2];
                    bytes[3] = (byte)(registers[2] >> 8);
                    bytes[4] = (byte)registers[1];
                    bytes[5] = (byte)(registers[1] >> 8);
                    bytes[6] = (byte)registers[0];
                    bytes[7] = (byte)(registers[0] >> 8);
                    break;

                default:
                    throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC, CDAB, DCBA");
            }

            // 如果系统是小端序，需要反转字节数组
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(bytes);
            }

            return bytes;
        }

        /// <summary>
        /// 将单个寄存器中的指定位转换为bool
        /// </summary>
        /// <param name="register">Modbus寄存器值</param>
        /// <param name="bitIndex">位索引(0-15)</param>
        public static bool ToBool(ushort register, int bitIndex)
        {
            if (bitIndex < 0 || bitIndex > 15)
                throw new ArgumentOutOfRangeException(nameof(bitIndex), "位索引必须在0-15之间");

            return (register & (1 << bitIndex)) != 0;
        }

        /// <summary>
        /// 将线圈状态数组转换为bool数组
        /// </summary>
        /// <param name="coils">Modbus线圈状态数组</param>
        public static bool[] ToBoolArray(bool[] coils)
        {
            return coils.ToArray();
        }

        /// <summary>
        /// 将寄存器数组转换为bool数组(每个寄存器16位)
        /// </summary>
        /// <param name="registers">Modbus寄存器数组</param>
        public static bool[] RegistersToBoolArray(ushort[] registers)
        {
            List<bool> result = new List<bool>();

            foreach (var register in registers)
            {
                for (int i = 0; i < 16; i++)
                {
                    result.Add((register & (1 << i)) != 0);
                }
            }

            return result.ToArray();
        }

        /// <summary>
        /// 将寄存器数组转换为指定索引的bool值
        /// </summary>
        /// <param name="registers">Modbus寄存器数组</param>
        /// <param name="absoluteBitIndex">绝对位索引(0 = 第一个寄存器的第0位)</param>
        public static bool ToBoolFromRegisters(ushort[] registers, int absoluteBitIndex)
        {
            int registerIndex = absoluteBitIndex / 16;
            int bitIndex = absoluteBitIndex % 16;

            if (registerIndex >= registers.Length)
                throw new ArgumentOutOfRangeException(nameof(absoluteBitIndex), "位索引超出寄存器范围");

            return ToBool(registers[registerIndex], bitIndex);
        }

        /// <summary>
        /// 将寄存器数组转换为ASCII字符串
        ///  // 示例1: 读取ASCII字符串(大端序)
        /// ushort[] registers = master.ReadHoldingRegisters(1, 0, 4);
        /// string asciiText = ModbusAsciiConverter.ToAscii(registers, "ABCD");
        /// Console.WriteLine($"ASCII字符串(ABCD): {asciiText}");
        /// </summary>
        /// <param name="registers">Modbus寄存器数组</param>
        /// <param name="endianness">字节顺序: ABCD, BADC</param>
        /// <param name="length">要转换的字符数(可选)</param>
        public static string ToAscii(ushort[] registers, string endianness = "ABCD", int? length = null)
        {
            if (registers == null || registers.Length == 0)
                return string.Empty;

            byte[] bytes = ConvertToBytesAscll(registers, endianness);

            // 如果指定了长度，只取前length个字节
            if (length.HasValue && length.Value < bytes.Length)
            {
                byte[] truncated = new byte[length.Value];
                Array.Copy(bytes, truncated, length.Value);
                bytes = truncated;
            }

            // 查找第一个null终止符(如果有)
            int nullTerminator = Array.IndexOf(bytes, (byte)0);
            if (nullTerminator >= 0)
            {
                byte[] terminated = new byte[nullTerminator];
                Array.Copy(bytes, terminated, nullTerminator);
                bytes = terminated;
            }

            return Encoding.ASCII.GetString(bytes);
        }

        private static byte[] ConvertToBytesAscll(ushort[] registers, string endianness)
        {
            byte[] bytes = new byte[registers.Length * 2];

            for (int i = 0; i < registers.Length; i++)
            {
                switch (endianness)
                {
                    case "ABCD": // 大端序 (默认)
                        bytes[i * 2] = (byte)(registers[i] >> 8);
                        bytes[i * 2 + 1] = (byte)registers[i];
                        break;

                    case "BADC": // 字节交换
                        bytes[i * 2] = (byte)registers[i];
                        bytes[i * 2 + 1] = (byte)(registers[i] >> 8);
                        break;

                    default:
                        throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC");
                }
            }

            return bytes;
        }

        /// <summary>
        /// 将ASCII字符串转换为寄存器数组
        /// </summary>
        /// <param name="text">ASCII字符串</param>
        /// <param name="endianness">字节顺序: ABCD, BADC</param>
        /// <param name="registerCount">目标寄存器数量(可选)</param>
        public static ushort[] FromAscii(string text, string endianness = "ABCD", int? registerCount = null)
        {
            if (string.IsNullOrEmpty(text))
                return new ushort[0];

            byte[] bytes = Encoding.ASCII.GetBytes(text);

            // 如果指定了寄存器数量，调整字节数组大小
            if (registerCount.HasValue)
            {
                int requiredBytes = registerCount.Value * 2;
                if (bytes.Length < requiredBytes)
                {
                    Array.Resize(ref bytes, requiredBytes);
                }
                else if (bytes.Length > requiredBytes)
                {
                    byte[] truncated = new byte[requiredBytes];
                    Array.Copy(bytes, truncated, requiredBytes);
                    bytes = truncated;
                }
            }

            ushort[] registers = new ushort[bytes.Length / 2 + (bytes.Length % 2 == 0 ? 0 : 1)];

            for (int i = 0; i < registers.Length; i++)
            {
                byte high = i * 2 < bytes.Length ? bytes[i * 2] : (byte)0;
                byte low = i * 2 + 1 < bytes.Length ? bytes[i * 2 + 1] : (byte)0;

                switch (endianness)
                {
                    case "ABCD": // 大端序 (默认)
                        registers[i] = (ushort)((high << 8) | low);
                        break;

                    case "BADC": // 字节交换
                        registers[i] = (ushort)((low << 8) | high);
                        break;

                    default:
                        throw new ArgumentException("不支持的字节顺序，请使用: ABCD, BADC");
                }
            }

            return registers;
        }
    }
}
